﻿namespace KAKA
{
    using System;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Drawing.Imaging;
    using System.Drawing.Text;
    using System.IO;
    using System.Windows.Forms;

    public partial class Util
    {
        internal Util()
        {
        }

        public class Image
        {
            internal Image()
            {
            }

            public static void Save(byte[] buffer, string path)
            {
                var directory = Path.GetDirectoryName(path);
                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                using (MemoryStream ms = new MemoryStream(buffer))
                using (Bitmap bitmap = new Bitmap(ms))
                {
                    bitmap.Save(path, ImageFormat.Jpeg);
                }
            }

            public static byte[] Compress(byte[] buffer, string mimeType, long quality)
            {
                using (MemoryStream ms = new MemoryStream(buffer))
                using (Bitmap source = new Bitmap(ms))
                {
                    ImageCodecInfo ici = GetEncoderInfo(mimeType);
                    Encoder encoderQuality = Encoder.Quality;
                    EncoderParameters encoderParameters = new EncoderParameters(2);
                    encoderParameters.Param[0] = new EncoderParameter(encoderQuality, quality);
                    Encoder encoderColorDepth = Encoder.ColorDepth;
                    encoderParameters.Param[1] = new EncoderParameter(encoderColorDepth, (long)ColorDepth.Depth32Bit);
                    using (MemoryStream buff = new MemoryStream())
                    {
                        source.Save(buff, ici, encoderParameters);
                        buff.Flush();
                        return buff.GetBuffer();
                    }
                }
            }

            public static byte[] Resize(byte[] buffer, int width, int height)
            {
                return Resize(buffer, width, height, ImageResizeMode.Normal);
            }

            public static byte[] Resize(byte[] buffer, int width, int height, ImageResizeMode mode)
            {
                using (MemoryStream ms = new MemoryStream(buffer))
                using (Bitmap source = new Bitmap(ms))
                {
                    int oldWidth = source.Width;
                    int oldHeight = source.Height;
                    switch (mode)
                    {
                        case ImageResizeMode.Normal:
                            break;
                        case ImageResizeMode.Width:
                            height = oldHeight * width / oldWidth;
                            break;
                        case ImageResizeMode.Height:
                            width = oldWidth * height / oldHeight;
                            break;
                        default:
                            break;
                    }
                    using (Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb))
                    using (Graphics g = Graphics.FromImage(bitmap))
                    {
                        foreach (var item in source.PropertyItems)
                        {
                            bitmap.SetPropertyItem(item);
                        }

                        g.CompositingQuality = CompositingQuality.GammaCorrected;
                        g.CompositingMode = CompositingMode.SourceOver;
                        g.SmoothingMode = SmoothingMode.HighQuality;
                        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                        g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                        g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                        g.Clear(Color.Transparent);
                        g.DrawImage(source, new Rectangle(0, 0, width, height), new Rectangle(0, 0, oldWidth, oldHeight), GraphicsUnit.Pixel);

                        return GetBinary(bitmap);
                    }
                }
            }

            public static byte[] Fill(byte[] buffer, int length)
            {
                using (MemoryStream ms = new MemoryStream(buffer))
                using (Bitmap source = new Bitmap(ms))
                {
                    int oldWidth = source.Width;
                    int oldHeight = source.Height;
                    int tWidth = oldWidth;
                    int tHeight = oldHeight;
                    int width = 0;
                    int height = 0;
                    if (oldWidth <= length)
                    {
                        width = length;
                        height = oldHeight * width / oldWidth;
                        tWidth = width;
                        tHeight = height;
                    }
                    if (height <= length)
                    {
                        height = length;
                        width = tWidth * height / tHeight;
                    }
                    using (Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb))
                    using (Graphics g = Graphics.FromImage(bitmap))
                    {
                        foreach (var item in source.PropertyItems)
                        {
                            bitmap.SetPropertyItem(item);
                        }

                        g.CompositingQuality = CompositingQuality.HighQuality;
                        g.SmoothingMode = SmoothingMode.HighQuality;
                        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                        g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                        g.Clear(Color.Transparent);
                        g.DrawImage(source, new Rectangle(0, 0, width, height), new Rectangle(0, 0, oldWidth, oldHeight), GraphicsUnit.Pixel);

                        return GetBinary(bitmap);
                    }
                }
            }

            public static byte[] Box(byte[] buffer, int length)
            {
                using (MemoryStream ms = new MemoryStream(buffer))
                using (Bitmap source = new Bitmap(ms))
                {
                    int oldWidth = source.Width;
                    int oldHeight = source.Height;
                    int width = 0;
                    int height = 0;
                    if (oldWidth >= oldHeight)
                    {
                        width = length;
                        height = oldHeight * width / oldWidth;
                    }
                    else
                    {
                        height = length;
                        width = oldWidth * height / oldHeight;
                    }
                    using (Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb))
                    using (Graphics g = Graphics.FromImage(bitmap))
                    {
                        foreach (var item in source.PropertyItems)
                        {
                            bitmap.SetPropertyItem(item);
                        }

                        g.CompositingQuality = CompositingQuality.HighQuality;
                        g.SmoothingMode = SmoothingMode.HighQuality;
                        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                        g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                        g.Clear(Color.Transparent);
                        g.DrawImage(source, new Rectangle(0, 0, width, height), new Rectangle(0, 0, oldWidth, oldHeight), GraphicsUnit.Pixel);

                        return GetBinary(bitmap);
                    }
                }
            }

            public static byte[] Square(byte[] buffer, int length)
            {
                using (MemoryStream ms = new MemoryStream(buffer))
                using (Bitmap source = new Bitmap(ms))
                {
                    int oldWidth = source.Width;
                    int oldHeight = source.Height;
                    int startX = 0;
                    int startY = 0;
                    if (oldWidth > length && oldHeight > length)
                    {
                        startX = (oldWidth - length) / 2;
                        startY = (oldHeight - length) / 2;
                    }
                    else if (oldWidth > length && oldHeight <= length)
                    {
                        startX = (oldWidth - length) / 2;
                    }
                    else if (oldHeight > length && oldWidth <= length)
                    {
                        startY = (oldHeight - length) / 2;
                    }
                    if (oldWidth < length || oldHeight < length)
                        return Cut(Fill(buffer, length), startX, startY, length, length);
                    else
                        return Cut(buffer, startX, startY, length, length);
                }
            }

            public static byte[] Cut(byte[] buffer, int startX, int startY, int width, int height)
            {
                using (MemoryStream ms = new MemoryStream(buffer))
                using (Bitmap source = new Bitmap(ms))
                {
                    int oldWidth = source.Width;
                    int oldHeight = source.Height;
                    using (Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb))
                    using (Graphics g = Graphics.FromImage(bitmap))
                    {
                        foreach (var item in source.PropertyItems)
                        {
                            bitmap.SetPropertyItem(item);
                        }

                        g.CompositingQuality = CompositingQuality.HighQuality;
                        g.SmoothingMode = SmoothingMode.HighQuality;
                        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                        g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                        g.Clear(Color.Transparent);
                        g.DrawImage(source, new Rectangle(0, 0, width, height), new Rectangle(startX, startY, width, height), GraphicsUnit.Pixel);

                        return GetBinary(bitmap);
                    }
                }
            }

            public static byte[] WatermarkImage(byte[] buffer, System.Drawing.Image watermark)
            {
                return WatermarkImage(buffer, watermark, WatermarkPosition.Default);
            }

            public static byte[] WatermarkImage(byte[] buffer, System.Drawing.Image watermark, WatermarkPosition position)
            {
                using (MemoryStream ms = new MemoryStream(buffer))
                using (Bitmap b = new Bitmap(ms))
                {
                    return Watermark(b, watermark, position);
                }
            }

            public static byte[] WatermarkImage(byte[] buffer, string watermarkPath)
            {
                return WatermarkImage(buffer, watermarkPath, WatermarkPosition.Default);
            }

            public static byte[] WatermarkImage(byte[] buffer, string watermarkPath, WatermarkPosition position)
            {
                using (Bitmap bitmap = new Bitmap(watermarkPath))
                {
                    return WatermarkImage(buffer, bitmap, position);
                }
            }

            public static byte[] WatermarkText(byte[] buffer, string text, string fontFamily)
            {
                return WatermarkText(buffer, text, fontFamily, WatermarkPosition.Default);
            }

            public static byte[] WatermarkText(byte[] buffer, string text, string fontFamily, WatermarkPosition position)
            {
                using (MemoryStream ms = new MemoryStream(buffer))
                using (Bitmap b = new Bitmap(ms))
                {
                    int oldWidth = b.Width;
                    int oldHeight = b.Height;
                    using (Bitmap bitmap = new Bitmap(oldWidth, oldHeight, PixelFormat.Format32bppArgb))
                    using (Graphics g = Graphics.FromImage(bitmap))
                    {
                        g.CompositingQuality = CompositingQuality.HighQuality;
                        g.SmoothingMode = SmoothingMode.HighQuality;
                        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                        g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                        g.Clear(Color.Transparent);
                        g.DrawImage(b, 0, 0, oldWidth, oldHeight);
                        int[] sizes = new int[] { 32, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4 };
                        Font crFont = null;
                        SizeF crSize = new SizeF();
                        for (int i = 0; i < sizes.Length; i++)
                        {
                            crFont = new Font(fontFamily, sizes[i], FontStyle.Regular);
                            crSize = g.MeasureString(text, crFont);
                            if ((ushort)crSize.Width < (ushort)oldWidth)
                                break;
                        }
                        using (Bitmap fb = new Bitmap((int)crSize.Width + 3, (int)crSize.Height + 3, PixelFormat.Format32bppArgb))
                        using (Graphics fg = Graphics.FromImage(fb))
                        {
                            PointF pt = new PointF(0, 0);
                            g.CompositingQuality = CompositingQuality.HighQuality;
                            g.SmoothingMode = SmoothingMode.HighQuality;
                            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                            g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                            fg.Clear(Color.Transparent);

                            using (Brush brush = new SolidBrush(Color.FromArgb(255, Color.Black)))
                            {
                                fg.DrawString(text, crFont, brush, pt.X, pt.Y + 1);
                                fg.DrawString(text, crFont, brush, pt.X + 1, pt.Y);
                            }

                            using (Brush brush = new SolidBrush(Color.FromArgb(255, Color.Black)))
                            {
                                fg.DrawString(text, crFont, brush, pt.X + 1, pt.Y + 1);
                                fg.DrawString(text, crFont, brush, pt.X, pt.Y + 2);
                                fg.DrawString(text, crFont, brush, pt.X + 2, pt.Y);
                            }

                            fg.DrawString(text, crFont, new SolidBrush(Color.White), pt.X, pt.Y, StringFormat.GenericDefault);
                            fg.Save();

                            return WatermarkAutoSize(b, fb, position);
                        }
                    }
                }
            }

            private static byte[] WatermarkAutoSize(System.Drawing.Image source, System.Drawing.Image watermark, WatermarkPosition position)
            {
                using (Bitmap b = new Bitmap(source))
                {
                    int oldWidth = b.Width;
                    int oldHeight = b.Height;

                    using (Bitmap bitmap = new Bitmap(oldWidth, oldHeight, PixelFormat.Format32bppArgb))
                    using (Graphics g = Graphics.FromImage(bitmap))
                    {
                        g.CompositingQuality = CompositingQuality.HighQuality;
                        g.SmoothingMode = SmoothingMode.HighQuality;
                        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                        g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                        g.Clear(Color.Transparent);
                        g.DrawImage(b, 0, 0, oldWidth, oldHeight);
                        using (ImageAttributes imageAttributes = new ImageAttributes())
                        {
                            ColorMap colorMap = new ColorMap();
                            colorMap.OldColor = Color.FromArgb(255, 0, 255, 0);
                            colorMap.NewColor = Color.FromArgb(0, 0, 0, 0);
                            ColorMap[] remapTable = { colorMap };
                            imageAttributes.SetRemapTable(remapTable, ColorAdjustType.Bitmap);
                            float[][] colorMatrixElements = {
　　　　　　　　　　　　         new float[] {1.0f, 0.0f, 0.0f, 0.0f, 0.0f},
　　　　　　　　　　　　         new float[] {0.0f, 1.0f, 0.0f, 0.0f, 0.0f},
　　　　　　　　　　　　         new float[] {0.0f, 0.0f, 1.0f, 0.0f, 0.0f},
　　　　　　　　　　　　         new float[] {0.0f, 0.0f, 0.0f, 0.3f, 0.0f},
　　　　　　　　　　　　         new float[] {0.0f, 0.0f, 0.0f, 0.0f, 1.0f}};
                            ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements);
                            imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
                            int xpos = 0;
                            int ypos = 0;
                            int watermarkWidth = 0;
                            int watermarkHeight = 0;
                            double bl = 1d;
                            if ((oldWidth > watermark.Width * 2) && (oldHeight > watermark.Height * 2))
                                bl = 1;
                            else if ((oldWidth > watermark.Width * 2) && (oldHeight < watermark.Height * 2))
                                bl = Convert.ToDouble(oldHeight / 2) / Convert.ToDouble(watermark.Height);
                            else if ((oldWidth < watermark.Width * 2) && (oldHeight > watermark.Height * 2))
                                bl = Convert.ToDouble(oldWidth / 2) / Convert.ToDouble(watermark.Width);
                            else
                            {
                                if ((oldWidth * watermark.Height) > (oldHeight * watermark.Width))
                                    bl = Convert.ToDouble(oldHeight / 2) / Convert.ToDouble(watermark.Height);
                                else
                                    bl = Convert.ToDouble(oldWidth / 2) / Convert.ToDouble(watermark.Width);
                            }
                            watermarkWidth = Convert.ToInt32(watermark.Width * bl);
                            watermarkHeight = Convert.ToInt32(watermark.Height * bl);
                            switch (position)
                            {
                                case WatermarkPosition.Top:
                                    xpos = (oldWidth - watermarkWidth) / 2;
                                    ypos = 12;
                                    break;
                                case WatermarkPosition.Bottom:
                                    xpos = (oldWidth - watermarkWidth) / 2;
                                    ypos = oldHeight - watermarkHeight - 12;
                                    break;
                                case WatermarkPosition.LeftTop:
                                    xpos = 24;
                                    ypos = 12;
                                    break;
                                case WatermarkPosition.LeftBottom:
                                    xpos = 24;
                                    ypos = oldHeight - watermarkHeight - 12;
                                    break;
                                case WatermarkPosition.RightTop:
                                    xpos = oldWidth - watermarkWidth - 24;
                                    ypos = 12;
                                    break;
                                case WatermarkPosition.RightBottom:
                                case WatermarkPosition.Default:
                                    xpos = oldWidth - watermarkWidth - 24;
                                    ypos = oldHeight - watermarkHeight - 12;
                                    break;
                                case WatermarkPosition.Left:
                                    xpos = 24;
                                    ypos = (oldHeight - watermarkHeight) / 2;
                                    break;
                                case WatermarkPosition.Right:
                                    xpos = oldWidth - watermarkWidth - 24;
                                    ypos = (oldHeight - watermarkHeight) / 2;
                                    break;
                                case WatermarkPosition.Center:
                                    xpos = (oldWidth - watermarkWidth) / 2;
                                    ypos = (oldHeight - watermarkHeight) / 2;
                                    break;
                            }
                            g.DrawImage(watermark, new Rectangle(xpos, ypos, watermarkWidth, watermarkHeight), 0, 0, watermark.Width, watermark.Height, GraphicsUnit.Pixel, imageAttributes);
                        }
                        return Compress(GetBinary(bitmap), "image/jpeg", 80L);
                    }
                }
            }

            private static byte[] Watermark(System.Drawing.Image source, System.Drawing.Image watermark, WatermarkPosition position)
            {
                using (Bitmap b = new Bitmap(source))
                {
                    int oldWidth = b.Width;
                    int oldHeight = b.Height;
                    using (Bitmap bitmap = new Bitmap(oldWidth, oldHeight, PixelFormat.Format32bppArgb))
                    using (Graphics g = Graphics.FromImage(bitmap))
                    {
                        g.CompositingQuality = CompositingQuality.HighQuality;
                        g.SmoothingMode = SmoothingMode.HighQuality;
                        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                        g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                        g.Clear(Color.Transparent);
                        g.DrawImage(b, 0, 0, oldWidth, oldHeight);
                        using (ImageAttributes imageAttributes = new ImageAttributes())
                        {
                            ColorMap colorMap = new ColorMap();
                            colorMap.OldColor = Color.FromArgb(255, 0, 255, 0);
                            colorMap.NewColor = Color.FromArgb(0, 0, 0, 0);
                            ColorMap[] remapTable = { colorMap };
                            imageAttributes.SetRemapTable(remapTable, ColorAdjustType.Bitmap);
                            float[][] colorMatrixElements = {
　　　　　　　　　　　　         new float[] {1.0f, 0.0f, 0.0f, 0.0f, 0.0f},
　　　　　　　　　　　　         new float[] {0.0f, 1.0f, 0.0f, 0.0f, 0.0f},
　　　　　　　　　　　　         new float[] {0.0f, 0.0f, 1.0f, 0.0f, 0.0f},
　　　　　　　　　　　　         new float[] {0.0f, 0.0f, 0.0f, 0.3f, 0.0f},
　　　　　　　　　　　　         new float[] {0.0f, 0.0f, 0.0f, 0.0f, 1.0f}};
                            ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements);
                            imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
                            int xpos = 0;
                            int ypos = 0;
                            int watermarkWidth = watermark.Width;
                            int watermarkHeight = watermark.Height;
                            switch (position)
                            {
                                case WatermarkPosition.Top:
                                    xpos = (oldWidth - watermarkWidth) / 2;
                                    ypos = 12;
                                    break;
                                case WatermarkPosition.Bottom:
                                    xpos = (oldWidth - watermarkWidth) / 2;
                                    ypos = oldHeight - watermarkHeight - 12;
                                    break;
                                case WatermarkPosition.LeftTop:
                                    xpos = 24;
                                    ypos = 12;
                                    break;
                                case WatermarkPosition.LeftBottom:
                                    xpos = 24;
                                    ypos = oldHeight - watermarkHeight - 12;
                                    break;
                                case WatermarkPosition.RightTop:
                                    xpos = oldWidth - watermarkWidth - 24;
                                    ypos = 12;
                                    break;
                                case WatermarkPosition.RightBottom:
                                case WatermarkPosition.Default:
                                    xpos = oldWidth - watermarkWidth - 24;
                                    ypos = oldHeight - watermarkHeight - 12;
                                    break;
                                case WatermarkPosition.Left:
                                    xpos = 24;
                                    ypos = (oldHeight - watermarkHeight) / 2;
                                    break;
                                case WatermarkPosition.Right:
                                    xpos = oldWidth - watermarkWidth - 24;
                                    ypos = (oldHeight - watermarkHeight) / 2;
                                    break;
                                case WatermarkPosition.Center:
                                    xpos = (oldWidth - watermarkWidth) / 2;
                                    ypos = (oldHeight - watermarkHeight) / 2;
                                    break;
                            }
                            g.DrawImage(watermark, new Rectangle(xpos, ypos, watermarkWidth, watermarkHeight), 0, 0, watermark.Width, watermark.Height, GraphicsUnit.Pixel, imageAttributes);
                        }
                        return Compress(GetBinary(bitmap), "image/jpeg", 80L);
                    }
                }
            }

            private static byte[] GetBinary(System.Drawing.Image bitmap)
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    bitmap.Save(ms, ImageFormat.Jpeg);
                    ms.Flush();
                    return ms.GetBuffer();
                }
            }

            private static ImageCodecInfo GetEncoderInfo(string mimeType)
            {
                ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
                foreach (ImageCodecInfo ici in encoders)
                {
                    if (ici.MimeType == mimeType)
                        return ici;
                }
                return null;
            }

            public static bool CheckFormat(ImageFormat rawFormat)
            {
                if (rawFormat != ImageFormat.Jpeg &&
                    rawFormat != ImageFormat.Gif &&
                    rawFormat != ImageFormat.Bmp &&
                    rawFormat != ImageFormat.Png)
                    return false;
                return true;
            }
        }

        public enum ImageResizeMode
        {
            Height = 2,
            Normal = 0,
            Width = 1,
        }
        public enum WatermarkPosition
        {
            Bottom = 2,
            Center = 5,
            Left = 4,
            LeftBottom = 1,
            LeftTop = 7,
            Right = 6,
            RightBottom = 3,
            RightTop = 9,
            Top = 8,
            Default = 0,
        }
    }
}
